// 项目入口文件

// 加载模块
const express = require('express');
const path = require('path');
const usersRouter = require('./routers/usersRouter');
const goodsRouter = require('./routers/goodsRouter');
const cors = require('cors');

// 创建express实例
const app = express();

// 配置cors跨域资源共享:

app.use(cors());

// cors中间件其实做了下列事情：
// app.all("*",function(req,res,next){
//     //设置允许跨域的域名，*代表允许任意域名访问
//     res.header("Access-Control-Allow-Origin","*")
//     //允许的header类型
//     res.header("Access-Control-Allow-Headers","Content-Type")
//     //允许的跨域请求方式 
//     res.header("Access-Control-Allow-Methods","POST,GET")
//     next()
// })

// 连接数据库
require('./db/connect');


/* // 前端的本地存储机制主要作用：存储用户状态
// 1.跨页面共享数据
// 2.持久化存储数据
// 客户端的cookie数据会随着http请求自动发送到服务端
// 服务端也可以设置或获取cookie数据
// 服务端使用cookie-parser插件操作cookie
// 1.安装
// npm i cookie-parser
// 2.加载模块
const cookieParser = require('cookie-parser');
// 3.使用插件
app.use(cookieParser());
// 使用了cookie-parser插件之后，在req请求对象中有一个cookies属性，包含客户端携带过来的cookie数据
// 使用了cookie-parser插件之后，在res响应对象中有一个cookie方法，用于设置客户端的cookie数据 */


/* // session会话控制
// http协议是无状态的
// 在web应用中 cookie 是一种记录用户状态的机制
// 在web应用中 session 是另一种记录用户状态的机制
// cookie存储在客户端（浏览器），session存储在服务端（服务器）
// session会话控制依赖cookie，express-session插件会自动操作cookie

// 使用 express-session 插件进行会话控制
// 1.安装
// npm i express-session
// 2.加载模块
const session = require('express-session');
// 3.使用插件
// app.use(session({配置}));
app.use(session({
    secret: 'hehe123',// 加密口令
    resave: true,// 无论session是否被修改都重新存储
    saveUninitialized: false,// 不存储新创建还未向session data添加数据的session
    name: 'nicai',// cookie的key名，默认为 connect.sid，值默认为session id
    cookie: {
        maxAge: 1000*60*10,//毫秒
        domain: 'localhost',
        path: '/'
    }
}));
// session由两部分组成：session id 和 session data
// 使用了express-session插件后，在req请求对象上有一个session属性，值为一个对象{...} -> session data
// 在向req.session对象中添加数据时，express-session插件会自动生成一个session id(唯一的标识)
// express-session插件自动在响应头中设置一个cookie，值为session id（session id存储在客户端的cookie中）
// session data存储在服务端的数据（内存或数据库） */


// token即令牌，俗称暗号，是一种加密字符串
// JWT 即 Json Web Token，是一种具体的token实现方式
// 官网：https://jwt.io/
// JWT是一种三段式加密字符串
// 如：'axxxxx.bxxxxxx.cxxxxxxx'

// 第一段：HEADER头信息，是一个JSON对象，使用base64编码
// header = {
//     "alg":"HS256",// 加密算法
//     "typ":"JWT"// token类型
// }
// base64(header) => 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'

// 第二段：PAYLOAD有效载荷，是一个JSON对象，使用base64编码
// payload = {
//     "sub": "1234567890",// 主题
//     "name": "John Doe",// 姓名
//     "iat": 1516239022,// 发布时间
//     "exp": 30,// 有效期，秒
//     ...
//     已登录用户信息
//     "username":"xiaoming",
//     "nickname":"小明",
// }
// base64(payload) => 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ'

// 第三段：SIGNATURE签名，使用base64编码后的header和payload，再加上 secret加密口令，使用HS256加密算法生成的哈希值
// HS256(base64(header)+'.'+base64(payload),secret加密口令) => 'SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'


// 在nodejs中使用JWT:
// 1.安装：
// npm i jsonwebtoken

// 2.加载模块
const jwt = require('jsonwebtoken');

// 3.生成token
// jwt.sign(obj,secret,other)返回一个token
// obj 要存储的信息
// secret 加密口令
// other 其他设置，如 有效期 expiresIn:秒 | '1d' | '7d'
// let info = {
//     "username":"xiaoming",
//     "nickname":"小明"
// }
// let token = jwt.sign(info,'hehe123',{expiresIn:3});
// console.log( token );// 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InhpYW9taW5nIiwibmlja25hbWUiOiLlsI_mmI4iLCJpYXQiOjE2ODQyMjQwMzksImV4cCI6MTY4NDIyNDA0Mn0.wtixqrNzG78UUIcGjroWICpv3H7h6Ft0PVq-sUjboiE'

// 4.验证token（解析）
// jwt.verify(token,secret,callback)
// token 要验证的token
// secret 加密口令
// callback 解析完成后的回调函数

/* // token正确
setTimeout(()=>{
    jwt.verify(token,'hehe123',(err,payload)=>{
        // err 验证成功时为null，验证失败时为错误对象
        // payload 加密字符串的第二段
        console.log( err );// null
        console.log( payload );
        // payload = {
        //     username: 'xiaoming',
        //     nickname: '小明',
        //     iat: 1684224391,
        //     exp: 1684224394
        // }
    })
},1000); */

/* // token过期
setTimeout(()=>{
    jwt.verify(token,'hehe123',(err,payload)=>{
        // err 验证成功时为null，验证失败时为错误对象
        // payload 加密字符串的第二段
        console.log( err );// {TokenExpiredError: jwt expired}
        console.log( payload );
        // payload = {
        //     username: 'xiaoming',
        //     nickname: '小明',
        //     iat: 1684224391,
        //     exp: 1684224394
        // }
    })
},4000); */

/* // token加密口令错误
setTimeout(()=>{
    jwt.verify(token,'haha123',(err,payload)=>{
        // err 验证成功时为null，验证失败时为错误对象
        // payload 加密字符串的第二段
        console.log( err );// {JsonWebTokenError: invalid signature}
        console.log( payload );
        // payload = {
        //     username: 'xiaoming',
        //     nickname: '小明',
        //     iat: 1684224391,
        //     exp: 1684224394
        // }
    })
},1000); */

/* // token伪造
setTimeout(()=>{
    jwt.verify(token+'abc','hehe123',(err,payload)=>{
        // err 验证成功时为null，验证失败时为错误对象
        // payload 加密字符串的第二段
        console.log( err );// {JsonWebTokenError: invalid signature}
        console.log( payload );
        // payload = {
        //     username: 'xiaoming',
        //     nickname: '小明',
        //     iat: 1684224391,
        //     exp: 1684224394
        // }
    })
},1000); */


// 指定静态资源目录www
app.use('/static',express.static(path.join(__dirname,'www')));

// 解析post请求体
app.use(express.urlencoded({extended:false}));// 解析查询字符串数据
app.use(express.json());// 解析json数据

// 使用路由表来匹配请求
app.use('/user',usersRouter);
app.use('/goods',goodsRouter);

// 监听9999端口
app.listen(9999,()=>{
    console.log( '--------------server started on port 9999--------------' );
});
